/*
 * LDIR
 *
 * LDIR, a GPS cartography application built for Let's Do It Romania eco
 * campaign.
 * Copyright (C) 2010 Genera Software <office@generasoftware.com>
 *
 * http://generasoftware.com/
 *
 * This program is free software; you can redistribute it and/or modify it under
 * the terms of the GNU General Public License as published by the Free Software
 * Foundation; either version 2 of the License, or (at your option) any later
 * version.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
 * details.
 *
 * You should have received a copy of the GNU General Public License along with
 * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
 * Place, Suite 330, Boston, MA 02111-1307 USA
 */
#include <eikmenub.h>
#include <akncontext.h>
#include <akntitle.h>
#include <aknnavide.h>
#include <aknnavi.h>
#include <stringloader.h>
#include <aknnotewrappers.h>
#include <akninfopopupnotecontroller.h>
#include <stringloader.h>
#include <hash.h>
#include <fieldsstringtable.h>
#include <LDIR.rsg>
#include <avkon.rsg>
#include "LDIRAppUi.h"
#include "Events.h"
#include "LDIR.hrh"
#include "LDIRWaste.hrh"
#include "LDIRSettings.hrh"
#include "LDIRMainView.h"
#include "LDIRWasteView.h"
#include "LDIRMapView.h"
#include "LDIRAboutView.h"
#include "LDIRSplashView.h"
#include "LDIRSettingsView.h"
#include "LDIRListCacheView.h"
#include "Settings.h"
#include "GPSLocator.h"
#include "GPSPositionData.h"
#include "gpsnavidecorator.h"
#include "gpsutils.h"
#include "WasteInfo.h"
#include "WasteCache.h"
#include "WSEngine.h"
#include "WSRequests.h"
#include "WsResponse.h"
#include "WSUtilities.h"
#include "Logger.h"

/**
 * Construct the CLDIRAppUi instance
 */
CLDIRAppUi::CLDIRAppUi()
    {
    }

/**
 * The appui's destructor removes the container from the control
 * stack and destroys it.
 */
CLDIRAppUi::~CLDIRAppUi()
    {
    delete iLdirNote;
    delete iWSEngine;
    delete iGpsLocator;
    LOGDESTROY();
    }

void CLDIRAppUi::InitializeContainersL()
    {
    CSettings& settings = CSettings::InstanceL();
    iLDIRSplashView = CLDIRSplashView::NewL();
    AddViewL( iLDIRSplashView );
    SetDefaultViewL( *iLDIRSplashView );
    iLDIRMainView = CLDIRMainView::NewL();
    settings.SettingsChanged
        += MAKEMETHODEVENTHANDLER0(void, CLDIRMainView, HandleSettingsChangedL, iLDIRMainView);
    AddViewL( iLDIRMainView );
    iLDIRWasteView = CLDIRWasteView::NewL();
    AddViewL( iLDIRWasteView );
    iLDIRMapView = CLDIRMapView::NewL();
    AddViewL( iLDIRMapView );
    iLDIRAboutView = CLDIRAboutView::NewL();
    AddViewL( iLDIRAboutView );
    iLDIRSettingsView = CLDIRSettingsView::NewL();
    AddViewL( iLDIRSettingsView );
    iLDIRListCacheView = CLDIRListCacheView::NewL();
    AddViewL( iLDIRListCacheView );
    }

void CLDIRAppUi::InitializeEnginesL()
    {
    iGpsLocator = CGPSLocator::NewL();

    // register GPS event handlers
    iGpsLocator->PositionUpdated
        += MAKEMETHODEVENTHANDLER1(void, const CGPSPositionData&, CLDIRAppUi, HandlePositionUpdateL, this);
    iGpsLocator->PositionUpdatedPartial
        += MAKEMETHODEVENTHANDLER1(void, const CGPSPositionData&, CLDIRAppUi, HandlePartialPositionUpdateL, this);
    iGpsLocator->PositionError
        += MAKEMETHODEVENTHANDLER1(void, TInt, CLDIRAppUi, HandlePositionErroL, this);
    iGpsLocator->PositioningMethod
        += MAKEMETHODEVENTHANDLER1(void, const TDesC&, CLDIRAppUi, HandlePositionMethodL, this);
    iGpsLocator->QualityLoss
        += MAKEMETHODEVENTHANDLER0(void, CLDIRAppUi, HandlePositionQualityLossL, this);
    iGpsLocator->TimedOut
        += MAKEMETHODEVENTHANDLER0(void, CLDIRAppUi, HandlePositionTimedOutL, this);

    iWSEngine = CWSEngine::NewL();
    }

void CLDIRAppUi::StartAddWasteViewL()
    {
    CSettings& settings = CSettings::InstanceL();
    CGPSPositionData& posData = iGpsLocator->PositionData();
    if ( !Math::IsNaN( posData.Position().Longitude() ) && !Math::IsNaN(
        posData.Position().Latitude() ) )
        {
        LOG(EVerbosityCore, _L("CLDIRAppUi::StartAddWasteViewL() - position is valid"));
        settings.SetWorkingWaste( CWasteInfo::NewL() );
        CWasteInfo* wasteInfo = settings.WorkingWaste();
        wasteInfo->iLongitude = posData.Position().Longitude();
        wasteInfo->iLatitude = posData.Position().Latitude();
        wasteInfo->iTime.UniversalTime();
        ActivateLocalViewL( iLDIRWasteView->Id() );
        }
    else
        {
        LOG(EVerbosityCore, _L("CLDIRAppUi::StartAddWasteViewL() - position is valid"));
        HBufC* note = StringLoader::LoadLC( R_NO_FIX );
        ShowNoteL( *note );
        CleanupStack::PopAndDestroy( note );
        }
    }

void CLDIRAppUi::UploadCacheL()
    {
    CSettings& settings = CSettings::InstanceL();
    if ( settings.PendingUploadCache().Count() )
        {
        if ( settings.UserSalt() == KNullDesC )
            {
            GetUserSaltL();
            }
        else
            {
            iWSEngine->WSRequestL( EWsReqCreateWastePoints,
                &settings.PendingUploadCache(), KNullDesC8,
                R_UPLOADING_WASTE_POINTS, this );

            }
        }
    }

void CLDIRAppUi::GetUserSaltL()
    {
    CSettings& settings = CSettings::InstanceL();

    if ( settings.Username() == KNullDesC )
        {
        GetUserCredentialsL();
        }
    TBuf8<KMaxName> param;
    param .Copy( settings.Username() );
    iWSEngine ->WSRequestL( EWsReqGetUserSalt, NULL, param, R_VALIDATING_USER,
        this );
    }

void CLDIRAppUi::ValidateUserL()
    {
    HBufC8* authString = CSettings::InstanceL().GenerateAuthStringLC();
    iWSEngine->WSRequestL( EWSReqValidateUser, NULL, *authString,
        R_VALIDATING_USER, this );
    CleanupStack::PopAndDestroy( authString );
    }

void CLDIRAppUi::GetUserCredentialsL()
    {
    CSettings& settings = CSettings::InstanceL();

    // Query user name and password
    TBuf<KMaxName> userName;
    TBuf<KMaxName> password;
    CAknMultiLineDataQueryDialog* dlg = CAknMultiLineDataQueryDialog::NewL(
        userName, password );

    if ( !dlg->ExecuteLD( R_DIALOG_USER_PASSWORD_QUERY ) )
        return; // No credentials given; must return EFalse

    settings.SetUsername( userName );
    settings.SetPassword( password );
    CSettings::InstanceL().StoreSettingsL();
    }

TBool CLDIRAppUi::QueryUser( TInt aResId )
    {
    CAknQueryDialog* dlg = CAknQueryDialog::NewL( CAknQueryDialog::ENoTone );
    dlg->PrepareLC( R_YES_NO_DIALOG );
    HBufC* text = StringLoader::LoadLC( aResId );
    dlg->SetPromptL( *text );
    CleanupStack::PopAndDestroy( text );
    return dlg->RunLD();
    }

/**
 * Handle a command for this appui (override)
 * @param aCommand command id to be handled
 */
void CLDIRAppUi::HandleCommandL( TInt aCommand )
    {
    TBool commandHandled = EFalse;
    switch ( aCommand )
        { // code to dispatch to the AppUi's menu and CBA commands is generated here
        case ECmdSplashCompleted:
            {
            iGpsLocator->StartL();
            ActivateLocalViewL( iLDIRMainView->Id() );
            break;
            }
        case ECmdMain:
            ActivateLocalViewL( iLDIRMainView->Id() );
            break;
        case ECmdAddWaste:
            StartAddWasteViewL();
            break;
        case ECmdList:
            ActivateLocalViewL( iLDIRListCacheView->Id() );
            break;
        case ECmdUpload:
            UploadCacheL();
            break;
        case ECmdGetUserSalt:
            GetUserSaltL();
            break;
        case ECmdValidateUser:
            ValidateUserL();
            break;
        case ECmdMapView:
            //ActivateLocalViewL( iLDIRMapView->Id() );
            break;
        case ECmdSettings:
            ActivateLocalViewL( iLDIRSettingsView->Id() );
            break;
        case ECmdAbout:
            ActivateLocalViewL( iLDIRAboutView->Id() );
            break;
        default:
            break;
        }

    if ( !commandHandled )
        {
        if ( aCommand == EAknSoftkeyExit || aCommand == EEikCmdExit )
            {
            Exit();
            }
        }
    }

/**
 * Override of the HandleResourceChangeL virtual function
 */
void CLDIRAppUi::HandleResourceChangeL( TInt aType )
    {
    CAknViewAppUi::HandleResourceChangeL( aType );
    }

/**
 * Override of the HandleKeyEventL virtual function
 * @return EKeyWasConsumed if event was handled, EKeyWasNotConsumed if not
 * @param aKeyEvent
 * @param aType
 */
TKeyResponse CLDIRAppUi::HandleKeyEventL( const TKeyEvent& aKeyEvent,
    TEventCode aType )
    {
    // The inherited HandleKeyEventL is private and cannot be called
    return EKeyWasNotConsumed;
    }

/**
 * Override of the HandleViewDeactivation virtual function
 *
 * @param aViewIdToBeDeactivated
 * @param aNewlyActivatedViewId
 */
void CLDIRAppUi::HandleViewDeactivation(
    const TVwsViewId& aViewIdToBeDeactivated,
    const TVwsViewId& aNewlyActivatedViewId )
    {
    CAknViewAppUi::HandleViewDeactivation( aViewIdToBeDeactivated,
        aNewlyActivatedViewId );
    }

void CLDIRAppUi::HandlePositionUpdateL( const CGPSPositionData& aPositionData )
    {
    iLDIRMainView->UpdatePositionL( aPositionData );
    iLDIRMainView->SetSatInUseL( aPositionData.SatelliteNumUsed() );
    }

void CLDIRAppUi::HandlePartialPositionUpdateL(
    const CGPSPositionData& aPartialPositionData )
    {
    HandlePositionUpdateL( aPartialPositionData );
    }

void CLDIRAppUi::HandlePositionQualityLossL()
    {

    }

void CLDIRAppUi::HandlePositionTimedOutL()
    {

    }

void CLDIRAppUi::HandlePositionErroL( TInt aError )
    {

    }

void CLDIRAppUi::HandlePositionMethodL( const TDesC& aMethod )
    {
    }

void CLDIRAppUi::ShowNoteL( const TDesC& aNote )
    {
    if ( !iLdirNote )
        {
        // Create the note once
        iLdirNote = CAknInfoPopupNoteController::NewL();
        }
    // Hide the note. The last note may be visible when creating the second
    iLdirNote->HideInfoPopupNote();

    // Set the time delay period before the popup is shown (in milliseconds)
    iLdirNote->SetTimeDelayBeforeShow( 300 );

    // Set the time period of how long the popup is in the view (in milliseconds)
    iLdirNote->SetTimePopupInView( 3 * 1000 );

    // Note text
    iLdirNote->SetTextL( aNote );

    // Note position
    TPoint pos = ClientRect().iBr;
    pos.iX = 0;
    iLdirNote->SetPositionAndAlignment( pos, EHCenterVTop );

    // Show note
    iLdirNote->ShowInfoPopupNote();
    }

/**
 * @brief Completes the second phase of Symbian object construction.
 * Put initialization code that could leave here.
 */
void CLDIRAppUi::ConstructL()
    {
    BaseConstructL( EAknEnableSkin );
    CSettings::InstanceL().LoadSettingsL();
    InitializeContainersL();
    InitializeEnginesL();
    }

////////////////////////////////////////////////////////////////////////////////
void CLDIRAppUi::HandleWsResponseErrorL( TInt aRequestId, TInt aErrorCode )
    {
    HBufC* note = StringLoader::LoadLC( R_UPLOAD_FAILED );
    ShowNoteL( *note );
    CleanupStack::PopAndDestroy( note );
    }

////////////////////////////////////////////////////////////////////////////////
void CLDIRAppUi::HandleWsResponseL( TInt aRequestId, TInt aResponseStatus,
    CWsResponse* aResponse )
    {
    CSettings& settings = CSettings::InstanceL();
    switch ( aRequestId )
        {
        case EWsReqGetUserSalt:
            TBuf<KMaxName> userSalt;
            userSalt.Copy( aResponse->Entity()->GetStr() );
            if ( userSalt.Length() )
                {
                settings.SetUserSalt( userSalt );
                settings.StoreSettingsL();
                PostCommandL( ECmdValidateUser );
                }
            else
                {
                if ( QueryUser( R_UNKNOWN_USER ) )
                    {
                    GetUserCredentialsL();
                    PostCommandL( ECmdGetUserSalt );
                    }
                }
            break;
        case EWSReqValidateUser:
            TBool success = aResponse->Entity()->GetBool();
            if ( success )
                {
                PostCommandL( ECmdUpload );
                }
            else
                {
                if ( QueryUser( R_INVALID_PASSWORD ) )
                    {
                    GetUserCredentialsL();
                    PostCommandL( ECmdValidateUser );
                    }
                }
            break;
        case EWsReqCreateWastePoints:
            HandleUploadResponseL( aResponse );
            break;
        default:
            break;
        }
    }

void CLDIRAppUi::AsyncHandleCommandL( const TInt& aCommand )
    {
    HandleCommandL( aCommand );
    }

void CLDIRAppUi::HandleUploadResponseL( CWsResponse* aResponse )
    {
    TInt successCount = 0;
    CSettings& settings = CSettings::InstanceL();
    CWasteCache& pendingCache = settings.PendingUploadCache();
    CWasteCache& localCache = settings.LocalCache();
    CEntity* root = aResponse->Entity();
    __ASSERT_ALWAYS(array_type == root->Type(), User::Invariant());
    Entities* entities = root->GetArray();
    TInt count = entities->Count();
    for ( TInt i = 0; i < count; ++i )
        {
        CWsObject * wsObject = CWsObject::NewLC( ( *entities )[i], EFalse );
        if ( wsObject->BoolAttribute( FieldsStringTable::EFldSucces ) )
            {
            TPtrC localId = wsObject->GetDesAttribute(
                FieldsStringTable::EFldLocalId );
            CWasteInfo * wasteInfo = pendingCache.GetById( localId );
            if ( wasteInfo )
                {
                TPtrC serverId = wsObject->GetDesAttribute(
                    FieldsStringTable::EFldServerID );
                wasteInfo->iId.Copy( serverId.Left( wasteInfo->iId.MaxLength() ) );
                localCache.AppendL( wasteInfo );
                pendingCache.Remove( wasteInfo );
                }
            ++successCount;
            }
        CleanupStack::PopAndDestroy( wsObject );
        }
    if ( successCount )
        {
        settings.StoreSettingsL();
        HBufC* note = StringLoader::LoadLC( R_UPLOAD_SUCCESS, successCount );
        ShowNoteL( *note );
        CleanupStack::PopAndDestroy( note );
        }
    }
